package org.semanticflash.rdf.graph
{
	
	import com.bigflexlib.ds.container.zet.IOSet;
	import com.bigflexlib.ds.container.zet.IOWSet;
	import com.bigflexlib.ds.container.zet.IRWSet;
	import com.bigflexlib.ds.container.zet.impl.OWSetWrapper;
	import com.bigflexlib.ds.container.zet.impl.RWSingleValueSet;
	
	import flash.events.Event;
	
	import org.semanticflash.rdf.graph.redirection.RDFTripleRedirection;
	import org.semanticflash.rdf.triple.IRDFTripleProvider;
	import org.semanticflash.rdf.triple.RDFTriple;

	
	
	/**
	 * 
	 * 
	 * 
	 * @author aldo.bucchi@gmail.com
	 * 
	 */
	public class RDFStatement extends RDFStatementBase implements IRDFTripleProvider
	{
		


		////////////////////////////////////////////////////
		// isRedirected
		////////////////////////////////////////////////////


		/**
		 * 
		 * A statement can be true ( isTrue==true ) but redirected.
		 * In that case, it becomes a source for another statement.
		 * If you wish to find out which one, inspect the "triples" property.
		 * 
		 * @return 
		 * 
		 */
		public function get isRedirected( ):Boolean
		{
			
			if ( _triples == null )
				return false;
			
			if ( _triples.size == 0 )
				return false;
			
			return true;		
		}




		////////////////////////////////////////////////////
		// triples
		////////////////////////////////////////////////////

		private var _triples:IOWSet;
		
		
		/**
		 * 
		 * When this statement is redirected it becomes a triple provider.
		 * This set will at most hold one triple ( the cannonical triple )
		 * 
		 * @return 
		 * 
		 */		
		public function get triples( ):IOSet
		{
			return _triples;		
		}





		///////////////////////////////////////////////////
		// etc
		///////////////////////////////////////////////////		

		/**
		 * 
		 * We keep a private copy of our triple's redirection
		 * 
		*/
		private var tripleRedirection:RDFTripleRedirection;




		/**
		* 
		*/
		private var targetSet:IRWSet;
		
		

		///////////////////////////////////////////////////
		// constructor 
		///////////////////////////////////////////////////		

		public function RDFStatement( triple:RDFTriple, graph:RDFGraph )
		{

			super( triple, graph );
			


			tripleRedirection = graph.redirectionContext.getTripleRedirection( triple );
			
			tripleRedirection.addEventListener( Event.CHANGE, tripleRedirection_change, false, 0, true );
			
			
			refresh( );
			
		}	
		
		
		
		
		private function refresh( ):void
		{
			
			refreshTriples( ); // this MUST be refreshed first
			
			refreshTargetSet( );
		
		}
		
		
		
		
		
		
		
		//////////////////////////////////////////////////
		// 
		//////////////////////////////////////////////////
		
		
		
		/**
		 * 
		 * A set can be published or used as an implicit source ( when it is redirected )
		 * 
		 */		
		private function refreshTargetSet( ):void
		{
			if ( tripleRedirection.target === _triple )
				setTargetSet( graph.publishedStatements );			
			else
				setTargetSet( graph.implicitSources );
		}
		
		
		
		
			
		private function setTargetSet( newTargetSet:IRWSet ):void
		{
			if ( targetSet == newTargetSet ) // dismiss
				return;
			
			if ( _isTrue ) // swap from one set to the other
			{
				targetSet.remove( this );
				newTargetSet.add( this );
			}
			targetSet = newTargetSet;
		}
		
		
		
		
		// this is where we hook into our superclass
		override protected function setIsTrue( newIsTrue:Boolean ):void
		{
			
			super.setIsTrue( newIsTrue );
			
			if ( newIsTrue )
				targetSet.add( this );
			else
				targetSet.remove( this );
		} 
		
		
		



		///////////////////////////////////////////////////
		// listen to triple redirection for changes
		///////////////////////////////////////////////////		
		
		private function tripleRedirection_change( event:Event ):void
		{
			refresh( );
		}


		
		private function refreshTriples( ):void
		{


			var targetTriple:RDFTriple = tripleRedirection.target;
			
			if ( targetTriple === this.triple ) // we never add ourselves. This is a memory optimization
			{
				
				if ( _triples != null )
					_triples.clear( );
				
				return;
			
			}

			
			
			lazyInitTriples( );
			
			
			///// update the set ////
		
			_triples.autoUpdateFlag.disable( );		
		
				_triples.clear( );
				
					_triples.add( targetTriple );
		
			_triples.autoUpdateFlag.enable( );		
			
		}		
		
		
		
		
		
		/**
		 * We don't crate the triples datastructure right away.
		 * It is used in rare cases ( only redirections )
		 * 
		 */		
		private function lazyInitTriples( ):void
		{
			if ( _triples == null )
			{
				_triples = new OWSetWrapper( new RWSingleValueSet( ) );			
			}
		}
		
		
		
		
		
		
		
		







		
		

		
	}


}





